package com.jeeplus.modules.common.excel.core;

import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.easy.core.exception.MessageException;
import com.easy.core.util.ResponseUtil;
import com.jeeplus.modules.api.importlog.service.ImportLogService;
import com.jeeplus.modules.common.constant.CommonConstants;
import com.jeeplus.modules.common.utils.ReadHeadListener;
import com.jeeplus.modules.da.utils.BaseRedisService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Transactional(readOnly = true)
public abstract class ExcelImportBaseService<T extends ExcelEntity> {

    private static final String TOTAL = "total";
    private static final String DONE = "done";

    @Autowired
    private BaseRedisService redis;

    @Autowired
    private ImportLogService importLogService;

    /**
     * 初始化参数
     */
    public abstract T initEntity(T excelEntity);

    /**
     * 判断列头是否正确
     * true:模板正确
     */
    public boolean checkHead(T excelEntity) {
        String[] titles = excelEntity.getTitles();
        if(titles == null){
            return false;
        }
        Map<String,String> headMap = excelEntity.getHeadMap();
        if(headMap == null){
            return false;
        }
        if(titles.length != headMap.size()){
            return false;
        }
        return true;
    }

    /**
     * 校验并生成正确和错误数据列表
     */
    public abstract void checkAndMakeDataList(T excelEntity);

    /**
     * 保存数据
     */
    public abstract void saveData(T excelEntity);

    /**
     * 导入excel主体方法
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
    public ResponseEntity importExcel(MultipartFile file, T t) throws Exception {

        T entity = initEntity(t);

        String fileName = file.getOriginalFilename();
        String extension = fileName.substring(fileName.lastIndexOf(".")+1);
        if(!"xlsx".equals(extension)){
            throw new MessageException("文件格式错误，请确认导入模板");
        }
        //缓存中如存在导入寝室的数据，不可继续操作
        if(StringUtils.isNotBlank(redis.getString(entity.getRedisKey()))){
            throw new MessageException("您有导入任务的进程，请查看导入结果或稍后再试。");
        }

        // 读取EXCEL
        InputStream inputStream = file.getInputStream();
        List<T> dataList = new ArrayList<>();
        //读取Excel 存入 datalist
        EasyExcel.read(inputStream, getTClass(), new ReadHeadListener<T>(enrollmentClassDataList -> {
            dataList.addAll(enrollmentClassDataList);
        })).sheet().headRowNumber(1).doRead();

        //表头对象
        Map<String,String> headMap = (Map<String, String>) dataList.get(0);
        entity.setHeadMap(headMap);

        // 判断表头是否正确
        if(!this.checkHead(entity)){
            throw new MessageException("使用的模板不正确，请下载正确模板");
        }

        //删除表头
        dataList.remove(0);
        // 移除文件中全空行记录
        if(dataList.size() == 0){
            throw new MessageException("上传的文件中无可用数据");
        }
        entity.setDataList(dataList);

        //读取文件中所有数据的总行数
        int totalCount = dataList.size();
        if(totalCount > CommonConstants.MAXROWCOUNT){
            throw new MessageException(CommonConstants.MAXROWERRMESSAGE);
        }
        entity.setTotalCount(totalCount);

        try{
            // 校验并生成正确和错误数据列表
            checkAndMakeDataList(entity);

            // 保存数据
            saveData(entity);

            // 保存导入失败的课程模板并写入日志表
            importLogService.saveErrLogExcel(entity.getErrorList(), totalCount, entity.getSuccessList().size(), entity.getErrorList().size(),entity.getImportScene(), getTClass());

        }catch (Exception e){
            e.printStackTrace();
            throw e;
        }finally {
            redis.deleteKey(entity.getRedisKey());
        }

        // 返回导入结果
        JSONObject result = new JSONObject();
        result.put("success",entity.getSuccessList().size());
        result.put("failed",entity.getErrorList().size());
        redis.deleteKey(entity.getRedisKey());
        return ResponseUtil.success(result);
    }

    /**
     * 获取 T.class
     */
    public Class<T> getTClass() {
        return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    /**
     * 更新进度
     */
    public void updateRedisProcess(T excelEntity){
        excelEntity.setDoneCount(excelEntity.getDoneCount() + 1);
        JSONObject importProcess = new JSONObject();
        importProcess.put(TOTAL,excelEntity.getTotalCount());
        importProcess.put(DONE,excelEntity.getDoneCount());
        redis.set(excelEntity.getRedisKey(), String.valueOf(importProcess),3L);
    }
}
